/** file AudioJack.cpp
    author belot.nicolas
*/

#include "AudioJack.h"
#include "Utility.h"
#include <iostream>

#ifdef HAVE_LIBJACK 

namespace libtrckr {

double* AudioJack::obuffer=0;
int AudioJack::cnt=0;

int process(jack_nframes_t nframes, void *arg){
	jack_default_audio_sample_t *in;
	AudioJack *out=(AudioJack*)arg;
	if( out->getFrames(nframes,AudioJack::obuffer)!=0){
		in = (jack_default_audio_sample_t *)jack_port_get_buffer (out->getPort(0), nframes);
		for(uint i=0;i<nframes;i++){
			in[i]=float(AudioJack::obuffer[i*out->channels()+0]);
		}
		in = (jack_default_audio_sample_t *)jack_port_get_buffer (out->getPort(1), nframes);
		for(uint i=0;i<nframes;i++){
			in[i]=float(AudioJack::obuffer[i*out->channels()+1]);
		}
	}else{
		std::cerr << "Buffer underun detected!" << std::endl;
	}	
	return 0;
}

AudioJack::AudioJack(){
	jack_status_t sta;
	_out[0]=NULL;
	_out[1]=NULL;
	rbuffer=0;
	_handler=jack_client_open("AudioJack", JackNullOption, &sta  );
	if(_handler==NULL){
			_state=UNAVAIL;
			std::cerr << "No Jack..." << std::endl;
			//trouble
	}else{
		jack_set_process_callback (_handler, process, this);
		_out[0] = jack_port_register (_handler, "input1",
		JACK_DEFAULT_AUDIO_TYPE,
		 JackPortIsInput, 0);
		_out[1] = jack_port_register (_handler, "input2",
		JACK_DEFAULT_AUDIO_TYPE,
		 JackPortIsInput, 0);
		_state=INVALID;
		channels(2);
		rbuffer=0;
		srate=jack_get_sample_rate(_handler);
		*capacity=srate;
	}
	cnt++;
}

AudioJack::AudioJack(const AudioJack &a){
	channels(a.channels());
	bitrate(a.bitrate());
	//_handler=malloc(sizeof(jack_client_t));
	//memcpy(_handler,a._handler,sizeof(jack_client_t));
	_state=INVALID;
	capacity=capacity;
	cnt++;
}

AudioJack::~AudioJack(){
	if(_out[0]!= NULL)
		jack_port_unregister(_handler,_out[0]);
	if(_out[1]!=NULL)
		jack_port_unregister(_handler,_out[1]);
	if(_handler!=NULL)
		jack_client_close(_handler);
	cnt--;
	if(rbuffer!=0){
		free(rbuffer);
	}
	if(cnt<=0){
		if(obuffer!=0) free(obuffer);
		/*if(tbuffer!=0) free(tbuffer);
		if(ibuffer!=0) free(ibuffer);
		if(xbuffer!=0) free(xbuffer);*/
	}
}

jack_port_t *AudioJack::getPort(int port){
	return _out[port];
}

void AudioJack::open(){
	if(_state!=UNAVAIL && !*lock){
		if (jack_activate (_handler)) {
			_state=UNAVAIL;
			return;
		}
		const char**ports = jack_get_ports (_handler, NULL, NULL,
				JackPortIsPhysical|JackPortIsOutput);
		if (ports == NULL) {
			//trouble
			_state=INVALID;
			return;
		}

		if (jack_connect (_handler, ports[0], jack_port_name (_out[0]))) {
			//trouble
			_state=INVALID;
			return;
		}
		if(ports[1]!=NULL){
			if (jack_connect (_handler, ports[1], jack_port_name (_out[1]))) {
			//trouble
			_state=INVALID;
			return;
		}	
		}else{
			std::cerr << "only one port active" << std::endl;
		}	
		free (ports);
		_state=OPEN;
		//allocate obuffer
		obuffer = (double*)malloc(sizeof(double)*1024*(srate/bitrate())*channels());
		sbuffer= (double*) malloc(sizeof(double)*srate*channels());
		*start=0;
		*end=0;
		*size=0;
		*capacity = (srate*channels());
		*lock=true;
	}
}

Audio::audio_state_t AudioJack::state() {
	return _state;
}

/*
void AudioJack::copy(Buffer& src){
	int element;
	src.setChannel(0);
	while(src.hasNextChannel()){
		for(uint i=0;i<src.size();i++){
			tbuffer[i]=src[i];
		}
		Utility::Interpolate(Utility::MONOTONE_CUBIC,xbuffer,tbuffer,src.size(),ibuffer, src.size()*srate/bitrate(),1);
		for(uint i=0;i<src.size()*srate/bitrate();i++){
			element=end+(i*src.channels())+src.getChannel();
			if(element>=capacity) element-=capacity;
			rbuffer[element]=ibuffer[i];
		}
		src.nextChannel();
	}
	end=element;
	size+=src.size()*src.channels()*srate/bitrate();
}
*/


int AudioJack::append(Buffer b){
	Buffer b2(b.size()*srate/bitrate());
	b2.channels(b.channels());
	Utility::Interpolate(Utility::MONOTONE_CUBIC, b,b2,srate/bitrate());
	if(size+(b2.size()*b2.channels())>capacity){
			return 0;
	}else{
			copy(b);
	}
	return b.size()*b.channels();
	
}

void AudioJack::param(std::string name, std::string value){}

void AudioJack::param(std::string name, double value){
	if(name=="buffer_size"){
		if(rbuffer==0){
			*capacity=value*srate;
		}
	}else if(name=="min_buffer_fill"){
		min_buffer=value*(*capacity);
	}
}
void AudioJack::param(std::string name, int value){}

void AudioJack::close(){
	jack_deactivate(_handler);
	_state=CLOSE;
	*lock=false;
}
}
#endif
